﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using Telerik.WinControls.UI;
using MetroTube.BusinessLogic;
using MetroTube.UI.Properties;
using Telerik.WinControls;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace MetroTube.UI
{
    public partial class MainForm : Form
    {
        private readonly Dictionary<WebClient, RadTileElement> videosToConvert = new Dictionary<WebClient, RadTileElement>();

        private readonly string tempPath = @".\temp";
        private readonly string downloadPath = @".\download";

        private WebClientDownloadManager webClientManager;

        private bool firstElement = true;


        public MainForm()
        {
            InitializeComponent();
            InitializePanorama();
            InitializeTextBox();
            InitializeWebClientManager();
            InitializeDirectories();
        }


        private void InitializePanorama()
        {
            _radPanorama.ScrollBarAlignment = HorizontalScrollAlignment.Bottom;
            _radPanorama.ScrollBarThickness = 1;

            _radPanorama.PanelImage = Resources.Background;
            _radPanorama.PanoramaElement.BackgroundImagePrimitive.ImageLayout = ImageLayout.Tile;

            _radPanorama.SizeChanged += new EventHandler(RadPanorama_SizeChanged);
            _radPanorama.PanoramaElement.ScrollBar.PropertyChanged += new PropertyChangedEventHandler(ScrollBar_PropertyChanged);
        }

        private void RadPanorama_SizeChanged(object sender, EventArgs e)
        {
            UpdateImageSize();
        }

        private void ScrollBar_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Maximum")
            {
                UpdateImageSize();
            }
        }

        private void UpdateImageSize()
        {
            int width = (_radPanorama.Width + _radPanorama.PanoramaElement.ScrollBar.Maximum) / 2;
            if (width < _radPanorama.Width)
            {
                width = _radPanorama.Width;
            }
            _radPanorama.PanelImageSize = new Size(width, _radPanorama.Height);

            _radPanorama.PanoramaElement.ScrollBar.PerformLast();
            _radPanorama.PanoramaElement.UpdateViewOnScroll();
        }


        private void InitializeTextBox()
        {
            _urlTextBox.SetWatermark(" Copy a youtube url here");
        }


        private void InitializeWebClientManager()
        {
            webClientManager = new WebClientDownloadManager();
            webClientManager.DownloadProgress += new Action(Manager_DownloadProgress);
            webClientManager.DownloadCompleted += new Action(Manager_DownloadCompleted);
        }

        private void Manager_DownloadProgress(object obj, EventArgs e)
        {
            _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = String.Format("Downloading {0} file(s), {1}% completed", webClientManager.ClientsCount, webClientManager.ClientsProgress)));
        }

        void Manager_DownloadCompleted(object obj, EventArgs e)
        {
            if (webClientManager.ClientsCount == 0)
                _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = String.Empty));
        }

        private void InitializeDirectories()
        {
            if (!Directory.Exists(downloadPath))
                Directory.CreateDirectory(downloadPath);

            if (!Directory.Exists(tempPath))
            {
                DirectoryInfo dir = Directory.CreateDirectory(tempPath);
                dir.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
            }
            
        }


        private void UrlTextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                if (_urlTextBox.Text.Equals("about"))
                {
                    _statusLabel.Text = "MetroTube 1.0 copyright © 2012 Salvatore Friscia";

                    e.Handled = true;

                    return;
                }

                _statusLabel.Text = "Loading...";

                var bg = new BackgroundWorker();
                bg.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
                bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker_RunWorkerCompleted);

                bg.RunWorkerAsync(_urlTextBox.Text);

                e.Handled = true;
            }
        }

        void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = SetVideo((string)e.Argument);
        }

        void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var result = (TileGroupElement)e.Result;

            if (result != null)
                _radPanorama.Groups.Add((TileGroupElement)e.Result);
        }

        private TileGroupElement SetVideo(string url)
        {
            try
            {
                YouTubeVideo youTubeVideo = VideoExtrapolation.GetVideoExtrapolation(new YouTubeHtmlWebPage(_urlTextBox.Text));

                int tileGroupColumnsCount = 4;
                int tileGroupRowsCount = 4;

                if (youTubeVideo.Links.Count<YouTubeVideoLink>() > 4)
                    tileGroupColumnsCount++;

                if (youTubeVideo.Links.Count<YouTubeVideoLink>() > 12)
                    tileGroupColumnsCount++;

                string thumbnailFile = string.Format(@"{0}\{1}.jpg", tempPath, youTubeVideo.Id);

                if (!File.Exists(thumbnailFile))
                    new WebClient().DownloadFile(new Uri(youTubeVideo.ImgUrl), thumbnailFile);

                TileGroupElement videoTileGroup = new TileGroupElement();
                videoTileGroup.RowsCount = tileGroupRowsCount;
                videoTileGroup.CellSize = new Size(135, 135);
                videoTileGroup.ForeColor = Color.White;
                videoTileGroup.Text = youTubeVideo.Name;

                if (firstElement)
                {
                    videoTileGroup.Margin = new System.Windows.Forms.Padding(120, 110, 20, 0);
                    firstElement = false;
                }
                else
                    videoTileGroup.Margin = new System.Windows.Forms.Padding(20, 110, 20, 0);

                RadTileElement imageTile = new RadTileElement();
                imageTile.BorderColor = Color.FromArgb(15, 109, 57);
                imageTile.BackgroundImage = Image.FromFile(thumbnailFile);
                imageTile.ColSpan = 2;
                videoTileGroup.Items.Add(imageTile);

                int i = 2;
                int y = 0;

                RadTileElement t = null;

                foreach (YouTubeVideoLink youTubeVideoLink in youTubeVideo.Links)
                {
                    var tile = CreateTileElement(string.Format("{0} (.{1})", youTubeVideoLink.Quality, youTubeVideoLink.Type), i, y);
                    tile.BackgroundImage = Resources.Video;

                    switch (youTubeVideoLink.Quality)
                    {
                        case "hd1080":
                            tile.BackColor = Color.FromArgb(0, 190, 226);
                            break;
                        case "hd720":
                            tile.BackColor = Color.FromArgb(232, 103, 35);
                            break;
                        case "large":
                            tile.BackColor = Color.FromArgb(94, 186, 15);
                            break;
                        case "medium":
                            tile.BackColor = Color.FromArgb(3, 67, 128);

                            if (youTubeVideoLink.Type.Equals("flv"))
                                t = tile;

                            break;
                        case "small":
                            tile.BackColor = Color.FromArgb(255, 176, 1);
                            break;
                        default:
                            break;
                    }

                    tile.AccessibleName = youTubeVideo.Name;
                    tile.Tag = youTubeVideoLink;

                    tile.Click += new EventHandler(Tile_Click);

                    videoTileGroup.Items.Add(tile);

                    IncreaseCounters(ref i, ref y, tileGroupColumnsCount);
                }

                if (t != null)
                {
                    var mp3Tile = CreateTileElement("audio (.mp3)", i, y);
                    mp3Tile.BackgroundImage = Resources.Music;
                    mp3Tile.AccessibleName = youTubeVideo.Name;
                    mp3Tile.AccessibleDescription = "mp3";
                    mp3Tile.Tag = (YouTubeVideoLink) t.Tag;
                    mp3Tile.Click += new EventHandler(AudioTile_Click);
                    videoTileGroup.Items.Add(mp3Tile);

                    IncreaseCounters(ref i, ref y, tileGroupColumnsCount);

                    var wmaTile = CreateTileElement("audio (.wma)", i, y);
                    wmaTile.BackgroundImage = Resources.Music;
                    wmaTile.AccessibleName = youTubeVideo.Name;
                    wmaTile.AccessibleDescription = "wma";
                    wmaTile.Tag = (YouTubeVideoLink)t.Tag;
                    wmaTile.Click += new EventHandler(AudioTile_Click);
                    videoTileGroup.Items.Add(wmaTile);
                }

                _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = string.Empty));

                return videoTileGroup;

            }
            catch (ArgumentException)
            {
                _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = "Url not valid"));
                return null;
            }
            catch (WebException)
            {
                _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = "Page not found"));
                return null;
            }

        }

        private RadTileElement CreateTileElement(string text , int i , int y)
        {
            RadTileElement tile = new RadTileElement();

            tile.Column = i;
            tile.Row = y;

            tile.Text = text;
            tile.Font = new System.Drawing.Font("Segoe UI", 11);
            tile.BorderColor = Color.FromArgb(15, 109, 57);
            tile.TextAlignment = ContentAlignment.BottomCenter;
            tile.TextImageRelation = TextImageRelation.TextAboveImage;
            tile.Padding = new System.Windows.Forms.Padding(0, 0, 0, 10);

            return tile;
        }

        private void IncreaseCounters( ref int i, ref int y, int modulus)
        {
            if ((++i % modulus) == 0)
            {
                i = 0;
                y++;
            }
        }

        private void Tile_Click(object sender, EventArgs e)
        {
            var tile = (RadTileElement)sender;
            YouTubeVideoLink link = tile.Tag as YouTubeVideoLink;

            Console.WriteLine(link);

            string fileName = Utility.FileNameValidString(tile.AccessibleName);
            string fileOutput = string.Format(@"{0}\{1} ({2}).{3}", downloadPath, fileName, link.Quality, link.Type);

            if (File.Exists(fileOutput))
            {
                _statusLabel.Text = String.Format("File just downloaded!");
                return;
            }

            WebClient webClient = new WebClient();
            webClientManager.Add(webClient);
            webClient.DownloadFileAsync(new Uri(link.Url), fileOutput);
        }

        private void AudioTile_Click(object sender, EventArgs e)
        {
            
            var tile = (RadTileElement)sender;
            YouTubeVideoLink link = tile.Tag as YouTubeVideoLink;

            string fileName = Utility.FileNameValidString(tile.AccessibleName);

            string fileInput = string.Format(@"{0}\{1} ({2}).{3}", tempPath, fileName, tile.AccessibleDescription, link.Type);
            string fileOutput = string.Format(@"{0}\{1}.{2}", downloadPath, fileName, tile.AccessibleDescription);

            Console.WriteLine("Input: {0}", fileInput);
            Console.WriteLine("Output: {0}", fileOutput);

            if (!File.Exists(fileInput))
            {
                Console.WriteLine("File doesn't exist. Start Downloading: {0}", fileInput);

                WebClient webClient = new WebClient();
                webClientManager.Add(webClient);
                webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(FileToConvert_DownloadCompleted);
                webClient.DownloadFileAsync(new Uri(link.Url), fileInput);

                videosToConvert.Add(webClient, tile);

                return;
            }

            new Thread(() => StartAudioConverting(fileInput, fileOutput, "128k")).Start();

        }

        void FileToConvert_DownloadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            Console.WriteLine("Download Completed");

            var webClient = (WebClient)sender;
            var tile = videosToConvert[webClient];

            tile.PerformClick();
        }

        private void StartAudioConverting(string input, string output, string bitrate)
        {
            _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = String.Format("Converting file...")));

            int result = Utility.FFmpegAudioConvert(input, output, bitrate);

            if (result > 0)
            {
                Console.WriteLine("File successfully converted!");
                File.Delete(input);
            }

            _statusLabel.Invoke(new MethodInvoker(() => _statusLabel.Text = string.Empty));
        }

    }
}
